package com.nightcat.dogvscat;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class GameView extends View {

	private Matrix mBirdMatrix = new Matrix();
	private Matrix mPigMatrix = new Matrix();
	/**
	 * 刷新消息发送的时间间隔，此值越小，刷新越快，动画越流畅，但是
	 * 不会低于硬件的最大刷新率限制。
	 */
	private static final int RUN_PERIOD = 20;
	private static final String TAG = "GameView";
	private Bitmap mBird = BitmapFactory.decodeResource(this.getResources(), R.drawable.bird);
	private Bitmap mPig = BitmapFactory.decodeResource(this.getResources(), R.drawable.pig);

	private Paint paint = new Paint();
	private Handler mHandler = new Handler();
	
	/**
	 * 物体本身的高宽。
	 */
	private float mPicWidth = mBird.getWidth();
	private float mPicHeight = mBird.getHeight();
	
	/**
	 * 每帧物体移动的距离，这个数值越大，物体移动速度越快。
	 */
	private static final float PACE_LENGTH = 6f;
	
//	private float mScreenWidth;
//	private float mScreenHeight;
	
	/**
	 * 物体当前的坐标。
	 */
	private float mCurrX;
	private float mCurrY;
	
	private float mPigCurrX;
	private float mPigCurrY;
	
	/**
	 * 抛物线的高和宽。
	 */
	private static  float PARABOLA_WIDTH = 800f;
	private static  float PARABOLA_HEIGHT = 280f;
	
	private  float mParabolaWidth;
	private  float mParabolaHeight;
	
	/**
	 * 物体在屏幕上的初始位置，此位置将用来计算抛物线公式。
	 */
	private static final float START_X = 100F;
	private static final float START_Y = 300F;
	
	private static final float PIG_START_X = 600F;
	private static final float PIG_START_Y = 300F;

	/**
	 * 左边物体的抛物线公式参数。
	 */
	float a,b,c;
	
	/**
	 * 右边物体的抛物线公式参数。
	 */
	float a1,b1,c1;
	
	//对主activity的引用。
	private DogvsCatActivity mActivity;
	
	/**
	 * 用来判断是否需要检测击中事件。
	 * 击中事件如果被检测到一次则停止检测后续的击中事件。
	 */
	boolean mDetectable = true;
	
	//player的位置框图。
	RectF mRect_leftPlayer;
//		//new RectF(0,300,100,480);
		//
	RectF mRect_rightPlayer;
		//new RectF(700,300,800,480);
	
	//飞行物的初始位和当前位置。
	RectF rectf_bird_origin = new RectF(0,0,mBird.getWidth(),mBird.getHeight());
	RectF rectf_pig_origin = new RectF(0,0,mPig.getWidth(),mPig.getHeight());
	
	RectF rectf_bird_current = new RectF();
	RectF rectf_pig_current = new RectF();
	
	//音效。
	private final int mCat_laugh;
	private final int mDog_laugh;
	private final int mMoan;
	
	//判断没有击中对手的情况。
	private boolean uncllided = true;
	
	//一次投掷动作以后的回调。
	public static interface Callback{
		int changeWindDirection();
		RectF getLeftPlayerRect();
		RectF getRightPlayerRect();
		void exchangePlayer();
	}
	
	private Callback mCallback;
	
	public GameView(Context context,AttributeSet attr){
		super(context,attr);
		mActivity = (DogvsCatActivity) context;
		//加载音乐。
		mCat_laugh = Util.loadMusic(R.raw.cat_laugh,mActivity);
		mDog_laugh = Util.loadMusic(R.raw.dog_laugh,mActivity);
		mMoan = Util.loadMusic(R.raw.moan,mActivity);
//		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//		mScreenHeight = wm.getDefaultDisplay().getHeight();
//		mScreenWidth = wm.getDefaultDisplay().getWidth();
		mCurrY = START_Y;
		mCurrX = START_X;
		
		mPigCurrY = PIG_START_Y;
		mPigCurrX = PIG_START_X;
		//初始化物体在屏幕上的位置。
		mBirdMatrix.postTranslate(START_X, START_Y);
		mPigMatrix.postTranslate(PIG_START_X, PIG_START_Y);
	}
	
	/**
	 * 注册一个回调函数。
	 * @return
	 */
	public void registerCallback(Callback callback){
		mCallback = callback;
	}
	
	public Callback getCallback(){
		return mCallback;
	}
	
	/**
	 * 抛物线公式，此公式的计算需要使用物体的初始位置
	 * 和抛物线的开口宽度和拱形的高度。
	 * @param currX
	 * @return
	 */
	public float getCurrY(float currX){
		return (float) (a*Math.pow(currX,2) + b*currX + c);
	}
	
	public float getPigCurrY(float currX){
		
		return (float) (a1*Math.pow(currX,2) + b1*currX + c1);
	}
	
	/**
	 * 使用matrix改变物体的位置和角度，结合handler使物体成抛物线运动。
	 */
	private Runnable mDoParabola = new Runnable(){
		@Override
		public void run() {
			mCurrX+=PACE_LENGTH;
			float y1 = getCurrY(mCurrX);
			
			GameView.this.rotate(1f, mCurrX+mPicWidth, y1+mPicHeight);
			GameView.this.translate(PACE_LENGTH,y1-mCurrY);
			mCurrY = y1;
			if(mCurrX<(START_X + mParabolaWidth)){
				mHandler.postDelayed(this, RUN_PERIOD);
			} else {
				
				if(uncllided){
					//播放取笑声音。
					Util.playMusic(mDog_laugh, mActivity);
				}
				
				/**
				 * 恢复到初始状态。
				 */
				mBirdMatrix.reset();
				mBirdMatrix.postTranslate(START_X, START_Y);
				mCurrX = START_X;
				mCurrY = START_Y;
				GameView.this.postInvalidate();
				mDetectable = true;
				mCallback.changeWindDirection();
				uncllided = true;
				mCallback.exchangePlayer();
			}
			
			//获得对方物体在屏幕上的位置。
			//((ImageView)mActivity.findViewById(R.id.dog)).getBackground();
			//Rect rect = ((ImageView)mActivity.findViewById(R.id.dog)).getBackground().getBounds();
			
			mBirdMatrix.mapRect(rectf_bird_current,rectf_bird_origin);
			
//			Log.d(TAG, "bird left: "+String.valueOf(rectf_bird_current.left));
//			Log.d(TAG, "bird right: "+String.valueOf(rectf_bird_current.right));
			
			//碰撞检测，当飞行物达到所在的坐标范围的时候才开始检测。
			if(rectf_bird_current.centerX() > mRect_rightPlayer.left && mDetectable){
				boolean cllided = CllideDefect(rectf_bird_current,mRect_rightPlayer);
				if(cllided){
					Log.d(TAG, "bird shoot at the right player.");
					mActivity.setRightLifeValue(0.1f);
					mDetectable = false;
					uncllided = false;
					//播放惨叫声音。
					Util.playMusic(mMoan, mActivity);
					
					//检测胜利状态。
					int status  = mActivity.checkWhoWin();
					showWin(status);
				}
			}
		}
	};
	
	
	/**
	 * 使用matrix改变物体的位置和角度，结合handler使物体成抛物线运动。
	 */
	private Runnable mPigDoParabola = new Runnable(){
		@Override
		public void run() {
			
			mPigCurrX -= PACE_LENGTH;
			float y1 = getPigCurrY(mPigCurrX);
			
			GameView.this.PIGrotate(-1f, mPigCurrX+mPicWidth, y1+mPicHeight);
			GameView.this.PIGtranslate(-PACE_LENGTH,y1 - mPigCurrY);
			mPigCurrY = y1;
			if(mPigCurrX>PIG_START_X - mParabolaWidth){
				mHandler.postDelayed(this, RUN_PERIOD);
			} else {
				if(uncllided){
				//播放取笑声音。
					Util.playMusic(mCat_laugh, mActivity);
				}
				
				/**
				 * 恢复到初始状态。
				 */
				mPigMatrix.reset();
				mPigMatrix.postTranslate(PIG_START_X, PIG_START_Y);
				mPigCurrX = PIG_START_X;
				mPigCurrY = PIG_START_Y;
				GameView.this.postInvalidate();
				mDetectable = true;
				mCallback.changeWindDirection();
				uncllided = true;
				mCallback.exchangePlayer();
			}
			
			mPigMatrix.mapRect(rectf_pig_current,rectf_pig_origin);
			
//			Log.d(TAG, "pig left: "+String.valueOf(rectf_pig_current.left));
//			Log.d(TAG, "pig right: "+String.valueOf(rectf_pig_current.right));
			//碰撞检测，当飞行物达到所在的坐标范围的时候才开始检测。
			if(rectf_pig_current.centerX() < mRect_leftPlayer.right && mDetectable){
				boolean cllided = CllideDefect(rectf_pig_current,mRect_leftPlayer);
				if(cllided){
					Log.d(TAG, "pig shoot at the right player.");
					mActivity.setLeftLifeValue(0.1f);
					mDetectable = false;
					uncllided = false;
					//播放惨叫的声音。
					Util.playMusic(mMoan, mActivity);
					
					//检测胜利状态。
					int status  = mActivity.checkWhoWin();
					showWin(status);
				}
			}
		}
	};
	
	public void translate(float deltaX, float deltaY){
		mBirdMatrix.postTranslate(deltaX, deltaY);
		this.postInvalidate();
	}
	
	public void rotate(float degress, float x, float y){
		mBirdMatrix.postRotate(degress, x, y);
		this.postInvalidate();
	}
	
	public void PIGtranslate(float deltaX, float deltaY){
		mPigMatrix.postTranslate(deltaX, deltaY);
		this.postInvalidate();
	}
	
	public void PIGrotate(float degress, float x, float y){
		mPigMatrix.postRotate(degress, x, y);
		this.postInvalidate();
	}
	

	@Override
	public void draw(Canvas canvas){
		super.draw(canvas);
		canvas.drawBitmap(mBird,mBirdMatrix,paint);
		canvas.drawBitmap(mPig,mPigMatrix,paint);
	}
	
	/**
	 * 
	 * @param widthFactor should be (0-1]
	 * @param heightFactor should be (0-1]
	 */
	public void startCatAction(float factor){
		if(factor > 0){
			mParabolaWidth = PARABOLA_WIDTH *factor;
		}
		if(factor >0){
			mParabolaHeight = PARABOLA_HEIGHT *factor;
		}
		
		/**
		 * 初始化抛物线参数。
		 */
		a = (float) (4*mParabolaHeight/Math.pow(mParabolaWidth,2));
		b = -a*(mParabolaWidth + 2*START_X);
		c = (float) (START_Y - a*Math.pow(START_X,2) - b*START_X);
		
		mHandler.postDelayed(mDoParabola, RUN_PERIOD);
	}
	
	/**
	 * 
	 * @param widthFactor should be (0-1]
	 * @param heightFactor should be (0-1]
	 */
	public void startDogAction(float factor){
		if(factor > 0){
			mParabolaWidth = PARABOLA_WIDTH *factor;
		}
		if(factor >0){
			mParabolaHeight = PARABOLA_HEIGHT *factor;
		}
		
		/**
		 * 初始化抛物线参数。
		 */
		a1 = (float) (4*mParabolaHeight/Math.pow(mParabolaWidth,2));
		b1 = a1*(mParabolaWidth - 2*PIG_START_X);
		c1 = (float) (PIG_START_Y - a1*Math.pow(PIG_START_X,2) - b1*PIG_START_X);
		
		mHandler.postDelayed(mPigDoParabola, RUN_PERIOD);
		
	}
	
	public void stopAction(){
		mHandler.removeCallbacks(mDoParabola);
		mHandler.removeCallbacks(mPigDoParabola);
	}
	
	/**
	 * 碰撞检测。
	 * @return true 发生碰撞， false 没有碰撞。
	 */
	private boolean CllideDefect(RectF a, RectF b){
		if(a.intersect(b)) return true;
		return false;
	}

	/**
	 * 得到左右player的位置，填充到全局变量中。
	 * 此方法必须在判断碰撞之前调用。
	 */
	public void init() {
		mRect_leftPlayer = mCallback.getLeftPlayerRect();
		mRect_rightPlayer = mCallback.getRightPlayerRect();
//		Log.d(TAG, "left_player:"+String.valueOf(mRect_leftPlayer));
//		Log.d(TAG, "right_player:"+String.valueOf(mRect_rightPlayer));
	}
	
	//展示胜负情况。
	private void showWin(int status){
		switch(status){
		case DogvsCatActivity.LEFT_WIN:
			Toast.makeText(mActivity, "The cat win", Toast.LENGTH_LONG).show();
			break;
		case DogvsCatActivity.RIGHT_WIN:
			Toast.makeText(mActivity, "The dog win", Toast.LENGTH_LONG).show();
			break;
		case DogvsCatActivity.NO_WIN:
			break;
		}
	}
}
